#!/bin/bash
#===============================================================================
# run.sh
#
# Run a set of experiments.
#===============================================================================

#-------------------------------------------------------------------------------
# Initialize the default behaviour of the script.
#-------------------------------------------------------------------------------

DEFAULT_UPDATE_EXAMPLES=0
DEFAULT_FLUSH_GREEN=0
DEFAULT_FLUSH_DISTR=1
DEFAULT_FLUSH_LOGGER=0
DEFAULT_REPEAT=1
DEFAULT_TARGET=""
DEFAULT_EXPERIMENTS=""

#-------------------------------------------------------------------------------
# Load the configuration.
#-------------------------------------------------------------------------------

test -x ./config.sh && . ./config.sh &>/dev/null

#-------------------------------------------------------------------------------
# Explain the command line options to the user.
#-------------------------------------------------------------------------------

function SHOW_OPTIONS() {
	EXIT_CODE=${1} ; shift

	cat <<EOF
Usage: ${0} [options] <jpf-target-file>"

Options [defaults]:

  -help           Display this message and exit

  -update=U       Update (U=1) or don't (U=0) .class and .jpf files. [U=${DEFAULT_UPDATE_EXAMPLES}]

  -flush-green=G  Flush (G=1) or don't flush (G=0) the green database. [G=${DEFAULT_FLUSH_GREEN}]

  -flush-distr=D  Flush (D=1) or don't (D=0) the distributed database. [D=${DEFAULT_FLUSH_DISTR}]

  -flush-log=L    Flush (L=1) or don't (L=0) the logging database. [L=${DEFAULT_FLUSH_LOGGER}]

  -exper=X        Add the X specification to the list of experiments.

  -help-exper     Show more detailed help about the experiments.

  -repeat=R       Repeat (R=1) or don't (R=0) identical experiments. [R=${DEFAULT_REPEAT}]

EOF
	exit ${EXIT_CODE}
}

#-------------------------------------------------------------------------------
# Explain the details of experiment command line options to the user.
#-------------------------------------------------------------------------------

function SHOW_EXPER_OPTIONS() {
	EXIT_CODE=${1} ; shift

	cat <<EOF
The "-exper=X" option adds X to the list of experiments to run.  It must appear
at least one more more times.  The specification X follows these rules:

  - X is a list of one/more terms Y,Y,Y... command separated, no spaces.

  - Y is N:M (e.g., "5:3"), where 1<=N<=8 and 1<=M<=3.

  - N:M means "run M instances of each of N blades".

  - If N is "A", then it is the same as writing "1:M,2:M,...,8:M".

  - If M is "A", then it is the same as writing "N:1,N:2,N:3".

  - If Y is "A:A", the experiment is run for all N and M.

EOF
	exit ${EXIT_CODE}
}

#-------------------------------------------------------------------------------
# Process the experiment option.
#-------------------------------------------------------------------------------

# Set the regular expression to recognize numbers.
NUMBER_RE='^[0-9]+$'

function PROCESS_EXPER_OPTION() {
	EXPER=${1} ; shift
	SPECS=`echo ${EXPER} | cut -c8-`
	for SPEC in `echo ${SPECS} | sed -e 's/,/ /g'` ; do
		NUM_BLADES=`echo ${SPEC} | cut -d':' -f1`
		NUM_JPF=`echo ${SPEC} | cut -d':' -f2`
		if [ "${NUM_BLADES}" == "A" ] ; then
			LIST_BLADES="1,2,3,4,5,6,7,8"
		elif ! [[ ${NUM_BLADES} =~ ${NUMBER_RE} ]] ; then
			echo "Error in blade specification \"${SPEC}\" (not a number)"
			SHOW_EXPER_OPTIONS 1
		elif [ ${NUM_BLADES} -lt 1 ] ; then
			echo "Error in blade specification \"${SPEC}\" (must be at least 1)"
			SHOW_EXPER_OPTIONS 1
		elif [ ${NUM_BLADES} -gt 8 ] ; then
			echo "Error in blade specification \"${SPEC}\" (must be at most 8)"
			SHOW_EXPER_OPTIONS 1
		else
			LIST_BLADES=${NUM_BLADES}
		fi
		if [ "${NUM_JPF}" == "A" ] ; then
			LIST_JPF="1,2,3"
		elif ! [[ ${NUM_JPF} =~ ${NUMBER_RE} ]] ; then
			echo "Error in instance specification \"${SPEC}\" (not a number)"
			SHOW_EXPER_OPTIONS 1
		elif [ ${NUM_JPF} -lt 1 ] ; then
			echo "Error in instance specification \"${SPEC}\" (must be at least 1)"
			SHOW_EXPER_OPTIONS 1
		elif [ ${NUM_JPF} -gt 3 ] ; then
			echo "Error in instance specification \"${SPEC}\" (must be at most 3)"
			SHOW_EXPER_OPTIONS 1
		else
			LIST_JPF=${NUM_JPF}
		fi
		for THE_BLADE in `echo ${LIST_BLADES} | sed -e 's/,/ /g'` ; do
			for THE_JPF in `echo ${LIST_JPF} | sed -e 's/,/ /g'` ; do
				EXPERIMENTS="${EXPERIMENTS};${THE_BLADE}:${THE_JPF}"
			done
		done
	done
}

#-------------------------------------------------------------------------------
# Initialize the behaviour (before processing command line options).
#-------------------------------------------------------------------------------

UPDATE_EXAMPLES=${DEFAULT_UPDATE_EXAMPLES}
FLUSH_GREEN=${DEFAULT_FLUSH_GREEN}
FLUSH_DISTR=${DEFAULT_FLUSH_DISTR}
FLUSH_LOGGER=${DEFAULT_FLUSH_LOGGER}
REPEAT=${DEFAULT_REPEAT}
PREV_TARGET=""
TARGET=${DEFAULT_TARGET}
EXPERIMENTS=${DEFAULT_EXPERIMENTS}

#-------------------------------------------------------------------------------
# Process the command line options.
#-------------------------------------------------------------------------------

while [ $# -gt 0 ] ; do
	OPTION=$1 ; shift
	case ${OPTION} in
		-help-exper) SHOW_EXPER_OPTIONS 0 ;;
		-help) SHOW_OPTIONS 0 ;;
		-update=0) UPDATE_EXAMPLES=0 ;;
		-update=*) UPDATE_EXAMPLES=1 ;;
		-flush-green=0) FLUSH_GREEN=0 ;;
		-flush-green=*) FLUSH_GREEN=1 ;;
		-flush-distr=0) FLUSH_DISTR=0 ;;
		-flush-distr=*) FLUSH_DISTR=1 ;;
		-flush-log=0) FLUSH_LOGGER=0 ;;
		-flush-log=*) FLUSH_LOGGER=1 ;;
		-repeat=0) REPEAT=0 ;;
		-repeat=*) REPEAT=1 ;;
		-exper=*) PROCESS_EXPER_OPTION ${OPTION} ;;
		-*) SHOW_OPTIONS 1 ;;
		*) PREV_TARGET=${TARGET} ; TARGET=${OPTION} ;;
	esac
done

#-------------------------------------------------------------------------------
# Check the script behaviour settings after options have been processed.
#-------------------------------------------------------------------------------

if [ "${EXPERIMENTS}" == "" ] ; then
	echo "No experiments specified"
	SHOW_OPTIONS 1
fi

if [ "${TARGET}" == "" ] ; then
	echo "No JPF target file specified"
	SHOW_OPTIONS 1
fi

if [ "${PREV_TARGET}" != "" ] ; then
	echo "More than one JPF target file specified"
	SHOW_OPTIONS 1
fi

#-------------------------------------------------------------------------------
# Start the actual work.
#-------------------------------------------------------------------------------

if [ "${UPDATE_EXAMPLES}" != "0" ] ; then
	./update.sh examples
fi

#if [ "${FLUSH_GREEN}" != "0" ] ; then
#	./redis.sh flush green
#fi
#
#if [ "${FLUSH_DISTR}" != "0" ] ; then
#	./redis.sh flush distr
#fi
#
#if [ "${FLUSH_LOGGER}" != "0" ] ; then
#	./redis.sh flush logger
#fi

ALREADY_PERFORMED=""

function PERFORM_EXPERIMENT() {
	EXPERIMENT=${1} ; shift
	if [ "${REPEAT}" == "0" ] ; then
		if [ `echo "${ALREADY_PERFORMED};" | grep -c ";${EXPERIMENT};"` -gt 0 ] ; then
			continue
		fi
	fi
	NUM_BLADES=`echo ${EXPERIMENT} | cut -d":" -f1`
	NUM_JPF=`echo ${EXPERIMENT} | cut -d":" -f2`
	#CUR_TIME=`ssh ${FIRST_HOST} "date +'%s'"`
	CUR_TIME=`ssh localhost "date +'%s'"`
	SHOW_TIME=`date -r $((${CUR_TIME})) +'%H:%M'`
	START_TIME=`date -r $((${CUR_TIME} + 120)) +'%H:%M'`
	FILE="${TARGET}_`date +'%Y%b%d-%H:%M:%S'`"
	BANNER="==== ${TARGET} ================================================================================"
	echo ${BANNER} | cut -c-79
	echo "Current time: ${SHOW_TIME}"
	echo "Start time:   ${START_TIME}"
	for (( BLADE=0; ${BLADE} < ${NUM_BLADES}; BLADE++ )) ; do
		HOST=${ALL_HOSTS[${BLADE}]}
		for (( INSTANCE=0; ${INSTANCE} < ${NUM_JPF}; INSTANCE++ )) ; do
			echo "./jpfat.sh ${START_TIME} ${TARGET} ${HOST}"
		done
	done
#	wait
#	echo "Copying results..."
##	gawk 'BEGIN{min=-1;max=-1}($2<min)||(min==-1){min=$2}($2>max)||(max==-1){max=$2}END{print max-min}' ${FILE} >> ${BASE}_summary.txt
	ALREADY_PERFORMED="${ALREADY_PERFORMED};${EXPERIMENT}"
}

for EXPERIMENT in `echo ${EXPERIMENTS} | sed -e 's/;/ /g'` ; do
	PERFORM_EXPERIMENT ${EXPERIMENT}
done

#===============================================================================
# End of run.sh
#===============================================================================
